﻿using System;
using Engine;
using Game;
using GameEntitySystem;
using TemplatesDatabase;

namespace Mekiasm
{
    public class ComponentRobit : ComponentEnergyMachine, IUpdateable
    {
        public ComponentBody componentBody;

        public UpdateOrder UpdateOrder => UpdateOrder.CreatureModels;
        public ComponentModel componentModel;
        public Vector3 EyePosition;
        public int HeadIndex;
        public int BodyIndex;
        public DynamicArray<ComponentBody> m_componentBodies = new DynamicArray<ComponentBody>();
        public ComponentEnergyMachine EnergyMachine;
        public Vector3? NextPoint;
        public Point3 HomePoint;
        public bool IsFollow;
        public bool IsCharge;
        public bool IsGetDrop;

        public ComponentAIMove ComponentAIMove;

        public ComponentRobit()
        {
            OutputPowerLimit = 32;
            InputPowerLimit = 32;
            MaxPower = 1024 * 1024 * 10;
        }
        public ComponentCreature FindTarget()
        {
            Vector3 position = componentBody.Position;
            ComponentCreature result = null;
            m_componentBodies.Clear();
            Bodies.FindBodiesAroundPoint(new Vector2(position.X, position.Z), 100f, m_componentBodies);
            for (int i = 0; i < m_componentBodies.Count; i++)
            {
                ComponentPlayer componentCreature = m_componentBodies.Array[i].Entity.FindComponent<ComponentPlayer>();
                if (componentCreature != null)
                {
                    return componentCreature;
                }
            }
            return result;
        }
        public void FindChargePad()
        {
            ComponentBlockEntity blockEntity = Entities.GetBlockEntity(HomePoint.X, HomePoint.Y, HomePoint.Z);
            if (blockEntity != null)
            {
                ComponentChargepad chargepad = blockEntity.Entity.FindComponent<ComponentChargepad>();
                if (chargepad != null)
                {
                    int chargeNum = (int)(OutputPowerLimit * 100);
                    if (chargepad.Power >= chargeNum && Power + chargeNum <= MaxPower)
                    {
                        chargepad.Power -= chargeNum;
                        Power += chargeNum;
                    }
                }
            }
            else
            {
                ComponentSpawn componentSpawn = Entity.FindComponent<ComponentSpawn>();
                componentSpawn.Despawn();
                Pickables.AddPickable(Robit.Index, 1, componentBody.Position, null, null);
            }
        }
        public ComponentPathFind PathFind;
        private SubsystemAudio Audio;
        private SubsystemTime Time;
        private SubsystemGameInfo GameInfo;
        private SubsystemPickables Pickables;
        private SubsystemBodies Bodies;
        private SubsystemBlockEntities Entities;
        private Pickable DescPick = null;
        public override void Load(ValuesDictionary valuesDictionary, IdToEntityMap idToEntityMap)
        {
            base.Load(valuesDictionary, idToEntityMap);
            PathFind = Entity.FindComponent<ComponentPathFind>();
            componentBody = Entity.FindComponent<ComponentBody>();
            componentModel = Entity.FindComponent<ComponentModel>();
            EnergyMachine = Entity.FindComponent<ComponentEnergyMachine>();
            Audio = Project.FindSubsystem<SubsystemAudio>();
            Time = Project.FindSubsystem<SubsystemTime>();
            GameInfo = Project.FindSubsystem<SubsystemGameInfo>();
            Pickables = Project.FindSubsystem<SubsystemPickables>();
            Bodies = Project.FindSubsystem<SubsystemBodies>();
            Entities = Project.FindSubsystem<SubsystemBlockEntities>();
            HeadIndex = componentModel.Model.FindMesh("Head").ParentBone.Index;
            BodyIndex = componentModel.Model.FindMesh("Body").ParentBone.Index;
            HomePoint = valuesDictionary.GetValue<Point3>("HomePoint");
            IsCharge = valuesDictionary.GetValue<bool>("IsCharge");
            IsFollow = valuesDictionary.GetValue<bool>("IsFollow");
            IsGetDrop = valuesDictionary.GetValue<bool>("IsGetDrop");
            CraftProgress = 0f;
            ComponentAIMove = Entity.FindComponent<ComponentAIMove>();
        }
        public override void Save(ValuesDictionary valuesDictionary, EntityToIdMap entityToIdMap)
        {
            base.Save(valuesDictionary, entityToIdMap);
            valuesDictionary.SetValue("HomePoint", HomePoint);
            valuesDictionary.SetValue("IsFollow", IsFollow);
            valuesDictionary.SetValue("IsCharge", IsCharge);
            valuesDictionary.SetValue("IsGetDrop", IsGetDrop);
        }
        public static int FindAcquireSlotForItem(IInventory inventory,int startIndex, int value)
        {
            for (int i = startIndex; i < inventory.SlotsCount; i++)
            {
                if (inventory.GetSlotCount(i) > 0 && inventory.GetSlotValue(i) == value && inventory.GetSlotCount(i) < inventory.GetSlotCapacity(i, value))
                {
                    return i;
                }
            }

            for (int j = startIndex; j < inventory.SlotsCount; j++)
            {
                if (inventory.GetSlotCount(j) == 0 && inventory.GetSlotCapacity(j, value) > 0)
                {
                    return j;
                }
            }

            return -1;
        }
        /// <summary>
        /// 填充物品
        /// </summary>
        /// <param name="value"></param>
        /// <param name="count">开始数量</param>
        /// <returns>剩余数量</returns>
        public new int AquireItems(int value,int count)
        {
            //18为机器人的背包起始格子
            int slotIndex = FindAcquireSlotForItem(EnergyMachine, 18, value);
            if (slotIndex < 0 || slotIndex > 34) return count;
            else
            {
                if (count > 0 && slotIndex == FindAcquireSlotForItem(EnergyMachine, 18, value))
                {
                    EnergyMachine.AddSlotItems(slotIndex, value, 1);
                    count--;
                }
                return count;
            }
        }

        public void Update(float dt)
        {
            if (Time.PeriodicGameTimeEvent(1.0, 0.0))
            {
                if (IsFollow && !IsCharge)
                {
                    ComponentCreature creature = FindTarget();
                    if (creature != null && Vector3.DistanceSquared(componentBody.Position, creature.ComponentBody.Position) > 100f && Power > 0)
                    {
                        PathFind.SetDestination(creature.ComponentBody.Position, 3f, 4f, 50, false, true, true, null);
                    }
                    else
                    {
                        //每隔30s随机走动
                        if (Time.PeriodicGameTimeEvent(30.0, 0.0))
                        {
                            Game.Random m_random = new Game.Random();
                            PathFind.SetDestination(componentBody.Position + new Vector3(6f * m_random.Float(-1f, 1f), 0f, 6f * m_random.Float(-1f, 1f)), 1f, 1f, 0, useRandomMovements: false, ignoreHeightDifference: true, raycastDestination: true, null);
                        }
                    }
                }
                Power -= Math.Min(16, Power);
            }
            if (Power <= 0 && Vector3.DistanceSquared(componentBody.Position, componentBody.Position) > 8f)
            {
                PathFind.SetDestination(new Vector3(HomePoint), 4f, 4f, 50, true, true, true, null);
            }
            if (IsCharge && Time.PeriodicGameTimeEvent(2.0, 0.0) && Vector3.DistanceSquared(new Vector3(HomePoint), new Vector3(HomePoint)) < 8f)
            {
                FindChargePad();
            }
            //寻找掉落物
            if (IsGetDrop)
            {
                if (DescPick == null)
                {
                    foreach (var p in Pickables.Pickables)
                    {
                        float sq = Vector3.DistanceSquared(p.Position, componentBody.Position);
                        //范围10格的掉落物
                        if (sq <= 100f)
                        {
                            DescPick = p;
                            break;
                        }
                    }
                }
                else if (DescPick.ToRemove) DescPick = null;
                else
                {
                    PathFind.SetDestination(DescPick.Position, 3f, 0.5f, 50, false, true, true, null);
                    float sq = Vector3.DistanceSquared(DescPick.Position, componentBody.Position);
                    if (sq <= 1f)
                    {
                        int count = AquireItems(DescPick.Value, DescPick.Count);
                        DescPick.Count = count;
                        if (count == 0) DescPick.ToRemove = true;
                        Audio.PlaySound("Audio/PickableCollected", 0.7f, -0.4f, DescPick.Position, 2f, autoDelay: false);
                    }
                }
            }

            if (ComponentAIMove.LookAtOrder.HasValue)
            {
                Vector3 forward = componentBody.Matrix.Forward;
                Vector3 v2 = ComponentAIMove.LookAtOrder.Value - EyePosition;
                float x = Vector2.Angle(new Vector2(forward.X, forward.Z), new Vector2(v2.X, v2.Z));
                float y = MathUtils.Asin(0.99f * Vector3.Normalize(v2).Y);
                ComponentAIMove.LookOrder = new Vector2(x, y) - ComponentAIMove.LookAngles;
            }

            if (ComponentAIMove.LookRandomOrder)
            {
                Matrix matrix = componentBody.Matrix;
                Vector3 v = Vector3.Normalize(ComponentAIMove.m_randomLookPoint - EyePosition);
                if (m_random.Float(0f, 1f) < 0.25f * dt || Vector3.Dot(matrix.Forward, v) < 0.2f)
                {
                    float s = m_random.Float(-5f, 5f);
                    float s2 = m_random.Float(-1f, 1f);
                    float s3 = m_random.Float(3f, 8f);
                    ComponentAIMove.m_randomLookPoint = EyePosition + s3 * matrix.Forward + s2 * matrix.Up + s * matrix.Right;
                }
                ComponentAIMove.LookAtOrder = ComponentAIMove.m_randomLookPoint;
            }

        }
    }
}
